use std::collections::HashSet;

use actix_web::web::Data;
use chrono::Local;
use sea_orm::{
    prelude::Expr,
    ActiveModelTrait,
    ActiveValue::{NotSet, Set},
    ColumnTrait, EntityTrait, IntoActiveModel, PaginatorTrait, QueryFilter, QueryOrder,
    QuerySelect, TransactionTrait,
};

use crate::{
    common::{
        app,
        error::ApiError,
        response::ApiResponse,
        types::{ApiPageResult, ApiResult},
    },
    config::{auth::AuthInfo, state::AppState},
    models::{
        entity::{
            prelude::{User, UserRole},
            user, user_role,
        },
        request::{
            common_request::IdRequest,
            user_req::{
                ChangePasswordRequest, CreateUserRequest, ModifyUser, PageUserRequest,
                UpdateUserRequest,
            },
        },
        response::user_res::{UserCreated, UserDetail, UserInfo, UserPage},
    },
    utils::password_util::PasswordUtil,
};

/// 创建用户
pub async fn create(
    state: Data<AppState>,
    req: CreateUserRequest,
    auth_info: AuthInfo,
) -> ApiResult<UserCreated> {
    log::info!("create user: {:?}", req);
    let user = User::find()
        .filter(user::Column::Deleted.eq(false))
        .filter(user::Column::Username.eq(&req.username))
        .one(&state.db)
        .await?;

    if user.is_some() {
        return Err(ApiError::BadRequest("用户名已存在"));
    }

    let now = chrono::Local::now().naive_local();

    let password = PasswordUtil::generate_random_password();
    let hashed_password = PasswordUtil::hash_password(&password)?;

    let user = user::ActiveModel {
        id: NotSet,
        username: Set(req.username),
        password: Set(hashed_password),
        nickname: Set(req.nickname),
        mobile: Set(req.mobile.unwrap_or_default()),
        status: Set(0),
        create_at: Set(now),
        update_at: Set(now),
        create_by: Set(auth_info.user_id),
        update_by: Set(auth_info.user_id),
        deleted: Set(false),
    };

    let txn = state.db.begin().await?;

    let user = user.insert(&txn).await?;

    let now = Local::now().naive_local();

    let is_root = auth_info.role_ids.contains(&app::ROLE_ROOT);

    let role_ids: HashSet<i32> = req.role_ids.into_iter().collect();
    log::info!("role_ids: {:?}", role_ids);
    if !role_ids.is_empty() {
        if !is_root {
            let auth_role_ids = UserRole::find()
                .select_only()
                .column(user_role::Column::RoleId)
                .filter(user_role::Column::UserId.eq(auth_info.user_id))
                .into_tuple()
                .all(&txn)
                .await?
                .into_iter()
                .collect();

            if !role_ids.is_subset(&auth_role_ids) {
                txn.rollback().await?;
                return Err(ApiError::Forbidden("无权限"));
            }
        }

        let mut user_role = vec![];

        for ri in role_ids {
            user_role.push(user_role::ActiveModel {
                id: NotSet,
                user_id: Set(user.id),
                role_id: Set(ri),
                create_at: Set(now),
                update_at: Set(now),
                create_by: Set(auth_info.user_id),
                update_by: Set(auth_info.user_id),
                deleted: Set(false),
            });
        }

        UserRole::insert_many(user_role).exec(&txn).await?;
    }

    txn.commit().await?;

    let result = UserCreated {
        user_id: user.id,
        username: user.username,
        nickname: user.nickname,
        password,
    };
    Ok(ApiResponse::ok(result))
}

/// 更新用户
pub async fn update(
    state: Data<AppState>,
    req: UpdateUserRequest,
    auth_info: AuthInfo,
) -> ApiResult<bool> {
    let user_id = auth_info.user_id;

    let user = User::find_by_id(user_id)
        .filter(user::Column::Deleted.eq(false))
        .one(&state.db)
        .await?
        .ok_or(ApiError::NotFound("用户不存在"))?;

    let mut user_active = user.into_active_model();
    user_active.nickname = Set(req.nickname);
    user_active.mobile = Set(req.mobile.unwrap_or_default());
    user_active.update_at = Set(Local::now().naive_local());
    user_active.update_by = Set(user_id);
    user_active.update(&state.db).await?;

    Ok(ApiResponse::ok(true))
}

/// 修改用户
pub async fn modify(
    state: Data<AppState>,
    req: ModifyUser,
    auth_info: AuthInfo,
) -> ApiResult<bool> {
    let is_root = auth_info.role_ids.contains(&1);

    if !is_root
        && auth_info
            .role_ids
            .iter()
            .any(|id| !req.role_ids.contains(id))
    {
        return Err(ApiError::Forbidden("无权限"));
    }

    let user = User::find_by_id(req.id)
        .filter(user::Column::Deleted.eq(false))
        .one(&state.db)
        .await?
        .ok_or(ApiError::NotFound("用户不存在"))?;

    let now = Local::now().naive_local();

    let mut user = user.into_active_model();
    user.nickname = Set(req.nickname);
    user.update_at = Set(now);
    user.update_by = Set(auth_info.user_id);

    let mut user_role = vec![];
    for rid in req.role_ids {
        user_role.push(user_role::ActiveModel {
            id: NotSet,
            user_id: Set(req.id),
            role_id: Set(rid),
            create_at: Set(now),
            update_at: Set(now),
            create_by: Set(auth_info.user_id),
            update_by: Set(auth_info.user_id),
            deleted: Set(false),
        });
    }

    let txn = state.db.begin().await?;

    user.update(&txn).await?;

    UserRole::update_many()
        .col_expr(user_role::Column::Deleted, Expr::value(true))
        .col_expr(user_role::Column::UpdateAt, Expr::value(now))
        .col_expr(user_role::Column::UpdateBy, Expr::value(auth_info.user_id))
        .filter(user_role::Column::UserId.eq(req.id))
        .exec(&txn)
        .await?;

    if !user_role.is_empty() {
        UserRole::insert_many(user_role).exec(&txn).await?;
    }

    txn.commit().await?;

    Ok(ApiResponse::ok(true))
}

/// 删除用户
pub async fn delete(state: Data<AppState>, req: IdRequest, auth_info: AuthInfo) -> ApiResult<bool> {
    let user_id = req.id;

    let user = User::find_by_id(user_id)
        .filter(user::Column::Deleted.eq(false))
        .one(&state.db)
        .await?
        .ok_or(ApiError::NotFound("用户不存在"))?;

    let now = Local::now().naive_local();

    let txn = state.db.begin().await?;

    let mut user_active = user.into_active_model();
    user_active.deleted = Set(true);
    user_active.update_at = Set(now);
    user_active.update_by = Set(auth_info.user_id);
    user_active.update(&txn).await?;

    UserRole::update_many()
        .col_expr(user_role::Column::Deleted, Expr::value(true))
        .col_expr(user_role::Column::UpdateAt, Expr::value(now))
        .col_expr(user_role::Column::UpdateBy, Expr::value(auth_info.user_id))
        .filter(user_role::Column::UserId.eq(user_id))
        .exec(&txn)
        .await?;

    txn.commit().await?;

    Ok(ApiResponse::ok(true))
}
/// 用户信息
pub async fn info(state: Data<AppState>, auth_info: AuthInfo) -> ApiResult<UserInfo> {
    let user_id = auth_info.user_id;

    let user = User::find_by_id(user_id)
        .filter(user::Column::Deleted.eq(false))
        .one(&state.db)
        .await?
        .ok_or(ApiError::NotFound("用户不存在"))?;

    if user.status != 0 {
        return Err(ApiError::Forbidden("用户已被禁用"));
    }

    Ok(ApiResponse::ok(user.into()))
}

/// 用户分页
pub async fn page(
    state: Data<AppState>,
    req: PageUserRequest,
    _auth_info: AuthInfo,
) -> ApiPageResult<UserPage> {
    let mut query = User::find()
        .filter(user::Column::Deleted.eq(false))
        .order_by_desc(user::Column::Id);

    if let Some(nickname) = req.nickname {
        if !nickname.is_empty() {
            query = query.filter(user::Column::Nickname.contains(nickname));
        }
    }

    let paginate = query.paginate(&state.db, req.per_page);

    let list = paginate.fetch_page(req.page - 1).await?;

    let count = paginate.num_items().await?;

    let list = list.into_iter().map(UserPage::from).collect();

    Ok(ApiResponse::ok_page(req.page, req.per_page, count, list))
}

/// 用户详情
pub async fn detail(
    state: Data<AppState>,
    req: IdRequest,
    _auth_info: AuthInfo,
) -> ApiResult<UserDetail> {
    let user_id = req.id;

    let user = User::find_by_id(user_id)
        .filter(user::Column::Deleted.eq(false))
        .one(&state.db)
        .await?
        .ok_or(ApiError::NotFound("用户不存在"))?;

    Ok(ApiResponse::ok(user.into()))
}

/// 修改密码
pub async fn change_password(
    state: Data<AppState>,
    req: ChangePasswordRequest,
    auth_info: AuthInfo,
) -> ApiResult<bool> {
    let user_id = auth_info.user_id;

    let user = User::find_by_id(user_id)
        .filter(user::Column::Deleted.eq(false))
        .one(&state.db)
        .await?
        .ok_or(ApiError::NotFound("用户不存在"))?;

    let has_password = &user.password;
    let old_password = req.old_password;
    let new_password = req.new_password;
    let cfm_password = req.confirm_password;

    if !new_password.eq(&cfm_password) {
        return Err(ApiError::BadRequest("两次输入的密码不一致"));
    }

    if !PasswordUtil::validate_password(&new_password)? {
        return Err(ApiError::BadRequest("密码不符合规则"));
    }

    if !PasswordUtil::verify_password(&old_password, has_password)? {
        return Err(ApiError::BadRequest("旧密码错误"));
    }

    let has_password = PasswordUtil::hash_password(&new_password)?;

    let mut user_active = user.into_active_model();
    user_active.password = Set(has_password);
    user_active.update_at = Set(Local::now().naive_local());
    user_active.update_by = Set(user_id);
    user_active.update(&state.db).await?;

    Ok(ApiResponse::ok(true))
}

/// 重置密码
pub async fn reset_password(
    state: Data<AppState>,
    req: IdRequest,
    _auth_info: AuthInfo,
) -> ApiResult<UserCreated> {
    let user_id = req.id;

    let password = PasswordUtil::generate_random_password();

    let has_password = PasswordUtil::hash_password(&password)?;

    let user = User::find_by_id(user_id)
        .filter(user::Column::Deleted.eq(false))
        .one(&state.db)
        .await?
        .ok_or(ApiError::NotFound("用户不存在"))?;

    let mut user_active = user.into_active_model();
    user_active.password = Set(has_password);
    user_active.update_at = Set(Local::now().naive_local());
    user_active.update_by = Set(user_id);
    let user = user_active.update(&state.db).await?;

    let user_info = UserCreated {
        user_id,
        username: user.username,
        nickname: user.nickname,
        password,
    };

    Ok(ApiResponse::ok(user_info))
}
